package aiku.numericalcontroloa.Service.EmployeeAttendance.Impl;

import aiku.numericalcontroloa.Base.Utils.BaseEnum;
import aiku.numericalcontroloa.Base.Utils.HttpStatus;
import aiku.numericalcontroloa.Base.Utils.Result;
import aiku.numericalcontroloa.Mapper.DepartmentManagement.EmployeeDepartmentMapper;
import aiku.numericalcontroloa.Mapper.EmployeeAttendance.AttendanceMapper;
import aiku.numericalcontroloa.Mapper.EmployeeAttendance.ClockinRuleMapper;
import aiku.numericalcontroloa.Mapper.UserMapper;
import aiku.numericalcontroloa.Model.Dto.EmployeeAttendance.AttendanceDto;
import aiku.numericalcontroloa.Model.Dto.PageSelect;
import aiku.numericalcontroloa.Model.Entity.DepartmentManagement.EmployeeDepartmentWithUser;
import aiku.numericalcontroloa.Model.Entity.EmployeeAttendance.Attendance;
import aiku.numericalcontroloa.Model.Entity.EmployeeAttendance.ClockinRule;
import aiku.numericalcontroloa.Model.Entity.User;
import aiku.numericalcontroloa.Model.Vo.EmployeeAttendance.AttendanceVo;
import aiku.numericalcontroloa.Model.Vo.EmployeeAttendance.ClockinRuleVo;
import aiku.numericalcontroloa.Service.DepartmentManagement.EmployeeDepartmentService;
import aiku.numericalcontroloa.Service.EmployeeAttendance.AttendanceService;
import aiku.numericalcontroloa.Service.EmployeeAttendance.ClockinRuleService;
import aiku.numericalcontroloa.common.utils.DateUtils;
import aiku.numericalcontroloa.common.utils.StringUtils;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.io.FilenameUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Time;
import java.time.*;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author 黄广庭
 * @Date 2024/2/26 17:19
 */
@Service
public class AttendanceServiceImpl implements AttendanceService {
    private final AttendanceMapper attendanceMapper;
    private final EmployeeDepartmentService employeeDepartmentService;
    private final EmployeeDepartmentMapper employeeDepartmentMapper;
    private final UserMapper userMapper;
    private final ClockinRuleMapper clockinRuleMapper;
    private final ClockinRuleService clockinRuleService;

    @Value("${numericalControlOa.excelPath}")
    private String excelPath;

    @Autowired
    private HttpServletResponse response;

    public AttendanceServiceImpl(AttendanceMapper attendanceMapper, EmployeeDepartmentService employeeDepartmentService,
            EmployeeDepartmentMapper employeeDepartmentMapper, UserMapper userMapper,
            ClockinRuleMapper clockinRuleMapper, ClockinRuleService clockinRuleService) {
        this.attendanceMapper = attendanceMapper;
        this.employeeDepartmentService = employeeDepartmentService;
        this.employeeDepartmentMapper = employeeDepartmentMapper;
        this.userMapper = userMapper;
        this.clockinRuleMapper = clockinRuleMapper;
        this.clockinRuleService = clockinRuleService;
    }

    @Override
    public Result addAttendance(AttendanceDto attendanceDto) {
        return null;
    }

    /**
     * 判断点是否在多边形内
     * 
     * @param point   经纬度
     * @param polygon 多边形经纬度组
     * @return
     */
    protected boolean isPointInPolygon(BigDecimal[] point, List<BigDecimal[]> polygon) {
        // console.log("point=>", point)
        // console.log("polygon=>", polygon)
        BigDecimal x = point[0], y = point[1];
        boolean inside = false;
        for (int i = 0, j = polygon.size() - 1; i < polygon.size(); j = i++) {
            BigDecimal xi = polygon.get(i)[0], yi = polygon.get(i)[1];
            BigDecimal xj = polygon.get(j)[0], yj = polygon.get(j)[1];
            // 点的射线和多边形的一条边重合，并且点在边上
            if ((yi.compareTo(yj) == 0 && yi.compareTo(y) == 0)
                    && ((xi.compareTo(x) > 0 && xj.compareTo(x) < 0) || (xi.compareTo(x) < 0 && xj.compareTo(x) > 0))) {
                return true;
            }
            // 判断线段两端点是否在射线两侧
            if ((yi.compareTo(y) < 0 && yj.compareTo(y) >= 0) || (yj.compareTo(y) < 0 && yi.compareTo(y) >= 0)) {
                // 求射线和线段的交点x坐标，交点y坐标当然是y
                BigDecimal intersect = xi.add(((y.subtract(yi)).multiply(xj.subtract(xi))).divide(yj.subtract(yi)));

                // 点在多边形的边上
                if (intersect.compareTo(x) == 0) {
                    return true;
                }
                // x大于点的x坐标，表示射线向右射出，如果穿过多边形边界，将 inside 取反
                if (intersect.compareTo(x) > 0) {
                    inside = !inside;
                }
            }
        }
        // 射线与多边形边界的交点数量为奇数时，点在多边形内部
        return inside;
    }

    @Override
    public Result deleteAttendance() {
        return null;
    }

    @Override
    @Transactional
    public Result updateAttendance(AttendanceDto attendanceDto) {
        if (attendanceDto == null || attendanceDto.getId() == null) {
            return new Result(HttpStatus.BAD_REQUEST, "参数为空(attendanceDto is null)");
        }
        // 查询打卡记录
        Attendance attendance = attendanceMapper.selectById(attendanceDto.getId());
        if (attendance == null) {
            return new Result(HttpStatus.BAD_REQUEST, "该打卡记录不存在");
        }
        // 打卡记录的打卡日期与今天的日期不匹配
        if (attendance.getClockingDate().compareTo(attendanceDto.getClockingDate()) != 0) {
            String msg = "当前日期(" + attendanceDto.getClockingDate() + ")与打卡日期(" + attendance.getClockingDate() + ")不一致";
            return new Result(HttpStatus.BAD_REQUEST, msg);
        }
        // 查询打卡规则
        ClockinRule clockinRule = clockinRuleMapper.selectByIdOnDelete(attendance.getClockinRuleId());
        if (clockinRule == null) {
            return new Result(HttpStatus.BAD_REQUEST, "该打卡规则不存在");
        }
        // 打卡规则类型（0个人规则，1部门规则）
        // 是否为个人规则打卡
        Boolean b = (attendance.getClockinType() == 0);

        // 部门打卡
        if (!b) {
            StringBuilder stringBuilder = new StringBuilder();
            // 设置打卡位置
            for (int i = 0; i < attendanceDto.getPosition().length; i++) {
                stringBuilder.append(attendanceDto.getPosition()[i]);
                if (i < attendanceDto.getPosition().length - 1) {
                    stringBuilder.append(",");
                }
            }
            attendance.setFciClockinPosition(stringBuilder.toString());
            // 将Date转为LocalTime
            LocalTime checkinTime = attendanceDto.getClockinTypeCheckoutTime().toInstant()
            .atZone(java.time.ZoneId.systemDefault()).toLocalTime();
            if (attendance.getForenoonCheckinTime() == null) {
                attendance.setFciClockinPosition(stringBuilder.toString());
                attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_NORMAL.getCodeInt());
                attendance.setForenoonCheckinTime(Time.valueOf(checkinTime));
            } else if (attendance.getForenoonCheckoutTime() == null) {
                attendance.setFcoClockoutPosition(stringBuilder.toString());
                attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_NORMAL.getCodeInt());
                attendance.setForenoonCheckoutTime(Time.valueOf(checkinTime));
            } else if (attendance.getAfternoonCheckinTime() == null) {
                attendance.setAciClockinPosition(stringBuilder.toString());
                attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_NORMAL.getCodeInt());
                attendance.setAfternoonCheckinTime(Time.valueOf(checkinTime));
            } else if (attendance.getAfternoonCheckoutTime() == null) {
                attendance.setAcoClockoutPosition(stringBuilder.toString());
                attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_NORMAL.getCodeInt());
                attendance.setAfternoonCheckoutTime(Time.valueOf(checkinTime));
            }
        }

        // 上午签到
        if (b && attendanceDto.getForenoonCheckinTime() != null) {
            StringBuilder stringBuilder = new StringBuilder();
            // 设置打卡位置
            for (int i = 0; i < attendanceDto.getPosition().length; i++) {
                stringBuilder.append(attendanceDto.getPosition()[i]);
                if (i < attendanceDto.getPosition().length - 1) {
                    stringBuilder.append(",");
                }
            }
            attendance.setFciClockinPosition(stringBuilder.toString());

            // 将Date转为LocalTime
            LocalTime checkinTime = attendanceDto.getForenoonCheckinTime().toInstant()
                    .atZone(java.time.ZoneId.systemDefault()).toLocalTime();
            // 设置上午签到时间
            attendance.setForenoonCheckinTime(Time.valueOf(checkinTime));
            // 往后推一分钟
            LocalTime localForenoonCheckin = clockinRule.getForenoonCheckinTime().toLocalTime().plusMinutes(1);
            Time newForenoonCheckinTime = Time.valueOf(localForenoonCheckin);
            if (DateUtils.compareToTime(attendance.getForenoonCheckinTime(), newForenoonCheckinTime) > 0) {
                // 打卡时间大于规则打卡时间
                // 迟到
                attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_BE_LATE.getCodeInt());
                // // 判定是否超过半小时，超过半小时算旷工
                // // 将java.sql.Time转换为java.time.LocalTime
                // LocalTime localTime = clockinRule.getForenoonCheckinTime().toLocalTime();
                // // 将时间往后推30分钟
                // LocalTime newLocalTime = localTime.plusMinutes(30);
                // // 将java.time.LocalTime转换回java.sql.Time
                // Time newTime = Time.valueOf(newLocalTime);
                // if (attendance.getForenoonCheckinTime().compareTo(newTime) > 0){
                // // 超过半小时，设置为旷工
                // attendance.setForenoonStasus(BaseEnum.CLOCKIN_STATUS_ABSENTEEISM.getCodeInt());
                // }else {
                // // 未超过半小时，设置为迟到
                // attendance.setForenoonStasus(BaseEnum.CLOCKIN_STATUS_BE_LATE.getCodeInt());
                // }
            } else {
                // 打卡时间小于规则打卡时间，正常打卡
                attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_NORMAL.getCodeInt());
            }
        }
        // 上午签退
        if (b && attendanceDto.getForenoonCheckoutTime() != null) {
            StringBuilder stringBuilder = new StringBuilder();
            // 设置打卡位置
            for (int i = 0; i < attendanceDto.getPosition().length; i++) {
                stringBuilder.append(attendanceDto.getPosition()[i]);
                if (i < attendanceDto.getPosition().length - 1) {
                    stringBuilder.append(",");
                }
            }
            attendance.setFcoClockoutPosition(stringBuilder.toString());

            // 将Date转为LocalTime
            LocalTime checkoutTime = attendanceDto.getForenoonCheckoutTime().toInstant()
                    .atZone(java.time.ZoneId.systemDefault()).toLocalTime();
            // 设置上午签退时间
            attendance.setForenoonCheckoutTime(Time.valueOf(checkoutTime));
            if (attendance.getForenoonCheckoutTime().compareTo(clockinRule.getForenoonCheckoutTime()) < 0) {
                // 签退时间小于规则签退时间，为早退
                if (attendance.getForenoonStatus().equals(BaseEnum.CLOCKIN_STATUS_BE_LATE.getCodeInt())) {
                    // 上午签到状态为迟到
                    // 设置为迟到且早退
                    attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_BE_LATE_LEAVE_EARLY.getCodeInt());
                } else if (attendance.getForenoonStatus().equals(BaseEnum.CLOCKIN_STATUS_NORMAL.getCodeInt())) {
                    // 上午签到状态为正常
                    // 设置为早退
                    attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_LEAVE_EARLY.getCodeInt());
                }
            }
        }
        // 下午签到
        if (b && attendanceDto.getAfternoonCheckinTime() != null) {
            StringBuilder stringBuilder = new StringBuilder();
            // 设置打卡位置
            for (int i = 0; i < attendanceDto.getPosition().length; i++) {
                stringBuilder.append(attendanceDto.getPosition()[i]);
                if (i < attendanceDto.getPosition().length - 1) {
                    stringBuilder.append(",");
                }
            }
            attendance.setAciClockinPosition(stringBuilder.toString());

            // 将Date转为LocalTime
            LocalTime checkinTime = attendanceDto.getAfternoonCheckinTime().toInstant()
                    .atZone(java.time.ZoneId.systemDefault()).toLocalTime();
            // 设置下午签到时间
            attendance.setAfternoonCheckinTime(Time.valueOf(checkinTime));
            // 往后退一分钟
            LocalTime localAfternoonCheckin = clockinRule.getAfternoonCheckinTime().toLocalTime().plusMinutes(1);
            Time newAfternoonCheckinTime = Time.valueOf(localAfternoonCheckin);
            if (attendance.getAfternoonCheckinTime().compareTo(newAfternoonCheckinTime) > 0) {
                // 打卡时间大于规则打卡时间
                // 迟到
                attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_BE_LATE.getCodeInt());
                // // 判定是否超过半小时，超过半小时算旷工
                // // 将java.sql.Time转换为java.time.LocalTime
                // LocalTime localTime = clockinRule.getAfternoonCheckinTime().toLocalTime();
                // // 将时间往后推30分钟
                // LocalTime newLocalTime = localTime.plusMinutes(30);
                // // 将java.time.LocalTime转换回java.sql.Time
                // Time newTime = Time.valueOf(newLocalTime);
                // if (attendance.getAfternoonCheckinTime().compareTo(newTime) > 0){
                // // 超过半小时，设置为旷工
                // attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_ABSENTEEISM.getCodeInt());
                // }else {
                // // 未超过半小时，设置为迟到
                // attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_BE_LATE.getCodeInt());
                // }
            } else {
                // 打卡时间小于规则打卡时间，正常打卡
                attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_NORMAL.getCodeInt());
            }
        }
        // 下午签退
        if (b && attendanceDto.getAfternoonCheckoutTime() != null) {
            StringBuilder stringBuilder = new StringBuilder();
            // 设置打卡位置
            for (int i = 0; i < attendanceDto.getPosition().length; i++) {
                stringBuilder.append(attendanceDto.getPosition()[i]);
                if (i < attendanceDto.getPosition().length - 1) {
                    stringBuilder.append(",");
                }
            }
            attendance.setAcoClockoutPosition(stringBuilder.toString());

            // 将Date转为LocalTime
            LocalTime checkoutTime = attendanceDto.getAfternoonCheckoutTime().toInstant()
                    .atZone(java.time.ZoneId.systemDefault()).toLocalTime();
            // 设置下午签退时间
            attendance.setAfternoonCheckoutTime(Time.valueOf(checkoutTime));
            if (attendance.getAfternoonCheckoutTime().compareTo(clockinRule.getAfternoonCheckoutTime()) < 0) {
                // 签退时间小于规则签退时间，为早退
                if (attendance.getAfternoonStatus().equals(BaseEnum.CLOCKIN_STATUS_BE_LATE.getCodeInt())) {
                    // 下午签到状态为迟到
                    // 设置为迟到且早退
                    attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_BE_LATE_LEAVE_EARLY.getCodeInt());
                } else if (attendance.getAfternoonStatus().equals(BaseEnum.CLOCKIN_STATUS_NORMAL.getCodeInt())) {
                    // 下午签到状态为正常
                    // 设置为早退
                    attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_LEAVE_EARLY.getCodeInt());
                }
            }
        }
        // 更新数据
        attendanceMapper.updateById(attendance);
        return Result.success("修改成功");
    }

    @Override
    public Result getAttendanceList(AttendanceDto attendanceDto) {
        if (attendanceDto == null) {
            return new Result(HttpStatus.BAD_REQUEST, "参数为空(attendanceDto is null)");
        }
        if (attendanceDto.getCurrentPage() == null || attendanceDto.getPageSize() == null) {
            return new Result(HttpStatus.BAD_REQUEST, "缺少分页参数");
        }

        // 总条数
        long total = 0L;
        List<User> userList = new ArrayList<>();

        // 条件查询
        // 1、先判断是否按部门查询，是则按部门，不是则查询用户列表
        if (attendanceDto.getDepartmentId() != null && !attendanceDto.getDepartmentId().isEmpty()) {
            // 1.1 如果按部门查询，则先查出该部门的所有下级部门
            PageSelect pageSelect = new PageSelect();
            pageSelect.setCurrentPage(attendanceDto.getCurrentPage());
            pageSelect.setPageSize(attendanceDto.getPageSize());
            pageSelect.setOffset(
                    (attendanceDto.getCurrentPage() * attendanceDto.getPageSize()) - attendanceDto.getPageSize());
            // 先查询该部门所有下级部门
            List<String> departmentIdList = new ArrayList<>();
            departmentIdList.add(attendanceDto.getDepartmentId());
            employeeDepartmentService.getDepartmentIdList(departmentIdList, departmentIdList);
            // 去重
            Set<String> departmentIds = new HashSet<>(departmentIdList);

            // 1.1.1 根据部门列表查询部门人员，可按姓名工号查询
            QueryWrapper<EmployeeDepartmentWithUser> employeeDepartmentLQW = new QueryWrapper<>();
            employeeDepartmentLQW.lambda().in(EmployeeDepartmentWithUser::getDepartmentId, departmentIds);
            if (attendanceDto.getNickName() != null && !attendanceDto.getNickName().isEmpty()) {
                employeeDepartmentLQW.and(lqw -> lqw.like("u.nick_name", attendanceDto.getNickName())
                        .or().like("u.empno", attendanceDto.getNickName()));
            } else {
                employeeDepartmentLQW.lambda().in(EmployeeDepartmentWithUser::getDepartmentId, departmentIds);
            }
            Set<String> userIdList = employeeDepartmentMapper
                    .selectListWithUser(pageSelect, employeeDepartmentLQW.lambda())
                    .stream().map(EmployeeDepartmentWithUser::getEmployeeId).collect(Collectors.toSet());
            // 1.1.2 处理数据得到员工列表
            if (userIdList.size() > 0) {
                userList.addAll(userMapper.selectBatchIds(userIdList));
                // 获取总条数
                Set<String> stringSet = employeeDepartmentMapper
                        .selectListWithUser(null, employeeDepartmentLQW.lambda()).stream()
                        .map(EmployeeDepartmentWithUser::getEmployeeId).collect(Collectors.toSet());
                LambdaQueryWrapper<Attendance> attendanceLQW = new LambdaQueryWrapper<>();
                attendanceLQW.select(Attendance::getEmployeeId).in(Attendance::getEmployeeId, stringSet)
                        .groupBy(Attendance::getEmployeeId);
                total = attendanceMapper.selectList(attendanceLQW).size();
            }
        } else {
            // 1.2 不按部门查询，则查询用户列表
            Page<User> userPage = new Page<>(attendanceDto.getCurrentPage(), attendanceDto.getPageSize());
            LambdaQueryWrapper<User> userLQW = new LambdaQueryWrapper<>();
            if (attendanceDto.getNickName() != null && !attendanceDto.getNickName().isEmpty()) {
                userLQW.eq(User::getState, BaseEnum.USER_INCUMBENCY.getCodeInt())
                        .and(lqw -> lqw.like(User::getNickName, attendanceDto.getNickName())
                                .or().like(User::getEmpno, attendanceDto.getNickName()));
            } else {
                userLQW.eq(User::getState, BaseEnum.USER_INCUMBENCY.getCodeInt());
            }
            userList.addAll(userMapper.selectPage(userPage, userLQW).getRecords());
            // 获取总条数
            LambdaQueryWrapper<Attendance> attendanceLQW = new LambdaQueryWrapper<>();
            attendanceLQW.select(Attendance::getEmployeeId)
                    .in(Attendance::getEmployeeId, userMapper.selectAllId())
                    .groupBy(Attendance::getEmployeeId);
            total = attendanceMapper.selectList(attendanceLQW).size();
        }

        Map<String, Object> map = new HashMap<>();
        map.put("total", total);
        map.put("attendanceVoList", getAttendanceVoList(userList, attendanceDto));
        return Result.success("查询成功", map);
    }

    /**
     * 处理成前端展示，和导出Excel的数据格式
     * 
     * @param userList
     * @param attendanceDto
     * @return
     */
    public List<AttendanceVo> getAttendanceVoList(List<User> userList, AttendanceDto attendanceDto) {
        List<AttendanceVo> attendanceVoList = new ArrayList<>();
        // 2.1 根据员工id集合查询员工出勤记录
        List<String> userIdList = userList.stream().map(User::getId).collect(Collectors.toList());
        LambdaQueryWrapper<Attendance> attendanceLQW = new LambdaQueryWrapper<>();
        attendanceLQW.in(Attendance::getEmployeeId, userIdList).orderByDesc(Attendance::getClockingDate);
        if (attendanceDto.getYear() != null) {
            // 根据年查询
            // attendanceLQW.apply("YEAR(clocking_date) = {0}",attendanceDto.getYear());
            // 年的第一天
            LocalDate yearStartDate = attendanceDto.getYear().atDay(1);
            attendanceLQW.between(Attendance::getClockingDate, yearStartDate, LocalDate.now());
        } else if (attendanceDto.getYearMonth() != null) {
            // 根据月查询
            // attendanceLQW.apply("DATE_FORMAT(clocking_date, '%Y-%m') =
            // {0}",attendanceDto.getYearMonth());
            // 月的第一天
            LocalDate monthStartDate = attendanceDto.getYearMonth().atDay(1);
            attendanceLQW.between(Attendance::getClockingDate, monthStartDate, LocalDate.now());
        } else if (attendanceDto.getYearMonthDay() != null) {
            // 根据日查询
            attendanceLQW.eq(Attendance::getClockingDate, attendanceDto.getYearMonthDay());
        } else {
            // 默认按当前月查询
            // 获取当前月份
            YearMonth yearMonth = YearMonth.now();
            // attendanceLQW.apply("DATE_FORMAT(clocking_date, '%Y-%m') = {0}",yearMonth);
            // 月的第一天
            LocalDate monthStartDate = yearMonth.atDay(1);
            attendanceLQW.between(Attendance::getClockingDate, monthStartDate, LocalDate.now());
        }
        List<Attendance> attendanceList = attendanceMapper.selectList(attendanceLQW);
        if (attendanceList.isEmpty()) {
            return attendanceVoList;
        }
        // 根据userId获取考勤记录
        Map<String, List<Attendance>> attendanceMap = new HashMap<>();
        for (Attendance attendance : attendanceList) {
            if (attendanceMap.containsKey(attendance.getEmployeeId())) {
                attendanceMap.get(attendance.getEmployeeId()).add(attendance);
            } else {
                List<Attendance> attendances = new ArrayList<>();
                attendances.add(attendance);
                attendanceMap.put(attendance.getEmployeeId(), attendances);
            }
        }

        // 根据打卡id集合查询打卡表
        Set<String> clockinRuleIdList = attendanceList.stream().map(Attendance::getClockinRuleId)
                .collect(Collectors.toSet());
        List<ClockinRule> clockinRuleList = clockinRuleMapper.selectBatchByIdWithDelete(clockinRuleIdList);
        Map<String, ClockinRule> clockinRuleMap = clockinRuleList.stream()
                .collect(Collectors.toMap(ClockinRule::getId, Function.identity()));
        for (User user : userList) {
            if (!attendanceMap.containsKey(user.getId())) {
                continue;
            }
            List<Attendance> userAttendanceList = attendanceMap.get(user.getId());
            // 2.2 遍历出勤记录，计算出本月的出勤状况
            int normalTotal = 0, // 正常打卡
                    lateTotal = 0, // 迟到
                    tardyTotal = 0, // 早退
                    absenteeismTotal = 0, // 旷工
                    leaveTotal = 0, // 请假
                    workOutsideTotal = 0, // 外勤
                    businessTripTotal = 0, // 出差
                    attendanceDays = 0; // 出勤天数
            // 处理出勤
            getUserAttendanceVoList(userAttendanceList, clockinRuleMap);
            for (Attendance attendance : userAttendanceList) {
                if (attendance.getForenoonStatus() != null) {
                    // 上午状态不为空
                    switch (attendance.getForenoonStatus()) {
                        // 正常打卡
                        case 0:
                            ++normalTotal;
                            if (attendance.getForenoonCheckoutTime() != null) {
                                ++normalTotal;
                            }
                            break;
                        // 迟到
                        case 1:
                            ++normalTotal;
                            ++lateTotal;
                            break;
                        // 早退
                        case 2:
                            ++normalTotal;
                            ++tardyTotal;
                            break;
                        // 旷工
                        case 3:
                            ++absenteeismTotal;
                            break;
                        // 请假
                        case 4:
                            ++leaveTotal;
                            break;
                        // 迟到&早退
                        case 5:
                            ++lateTotal;
                            ++tardyTotal;
                            break;
                        // 迟到&未签退
                        case 7:
                            ++lateTotal;
                            break;
                    }
                }
                if (attendance.getAfternoonStatus() != null) {
                    // 下午状态不为空
                    switch (attendance.getAfternoonStatus()) {
                        // 正常打卡
                        case 0:
                            ++normalTotal;
                            if (attendance.getAfternoonCheckoutTime() != null) {
                                ++normalTotal;
                            }
                            break;
                        // 迟到
                        case 1:
                            ++normalTotal;
                            ++lateTotal;
                            break;
                        // 早退
                        case 2:
                            ++normalTotal;
                            ++tardyTotal;
                            break;
                        // 旷工
                        case 3:
                            ++absenteeismTotal;
                            break;
                        // 请假
                        case 4:
                            ++leaveTotal;
                            break;
                        // 迟到&早退
                        case 5:
                            ++lateTotal;
                            ++tardyTotal;
                            break;
                        // 迟到&未签退
                        case 7:
                            ++lateTotal;
                            break;
                    }
                }
                if (attendance.getClockinType().equals(1)) {
                    // 打卡类型为外勤
                    ++workOutsideTotal;
                } else if (attendance.getClockinType().equals(2)) {
                    // 打卡类型为出差
                    ++businessTripTotal;
                }
                if (attendance.getForenoonStatus() != null && attendance.getAfternoonStatus() != null) {
                    // 上午和下午的打卡状态不为空
                    if ((attendance.getForenoonStatus() == 0 || attendance.getAfternoonStatus() == 0) ||
                            (attendance.getForenoonStatus() == 1 || attendance.getAfternoonStatus() == 1) ||
                            (attendance.getForenoonStatus() == 2 || attendance.getAfternoonStatus() == 2) ||
                            (attendance.getForenoonStatus() == 5 || attendance.getAfternoonStatus() == 5)) {
                        // 上午或者下午的打卡状态为正常，或者迟到，或者早退，或者迟到早退
                        // 出勤天数加1
                        ++attendanceDays;
                    }
                }
            }
            AttendanceVo attendanceVo = new AttendanceVo();
            attendanceVo.setEmployeeId(user.getId());
            attendanceVo.setNickName(user.getNickName());
            attendanceVo.setNormalTotal(normalTotal);
            attendanceVo.setLateTotal(lateTotal);
            attendanceVo.setTardyTotal(tardyTotal);
            attendanceVo.setAbsenteeismTotal(absenteeismTotal);
            attendanceVo.setLeaveTotal(leaveTotal);
            attendanceVo.setWorkOutsideTotal(workOutsideTotal);
            attendanceVo.setBusinessTripTotal(businessTripTotal);
            attendanceVo.setAttendanceDays(attendanceDays);
            attendanceVoList.add(attendanceVo);
        }
        return attendanceVoList;
    }

    @Override
    public Result getUserAttendanceList(AttendanceDto attendanceDto) {
        if (attendanceDto == null ||
                (attendanceDto.getEmployeeId() == null || attendanceDto.getEmployeeId().isEmpty())) {
            return new Result(HttpStatus.BAD_REQUEST, "参数为空(attendanceDto is null)");
        }
        if (attendanceDto.getCurrentPage() == null && attendanceDto.getPageSize() == null) {
            return new Result(HttpStatus.BAD_REQUEST, "缺少分页参数");
        }
        Page<Attendance> page = new Page<>(attendanceDto.getCurrentPage(), attendanceDto.getPageSize());
        LambdaQueryWrapper<Attendance> attendanceLQW = new LambdaQueryWrapper<>();
        attendanceLQW.orderByDesc(Attendance::getClockingDate)
                .eq(Attendance::getEmployeeId, attendanceDto.getEmployeeId());
        if (attendanceDto.getYear() != null) {
            // 根据年查询
            // attendanceLQW.apply("YEAR(clocking_date) = {0}",attendanceDto.getYear());
            // 年的第一天
            LocalDate yearStartDate = attendanceDto.getYear().atDay(1);
            LocalDate yearEndDate = attendanceDto.getYearMonth().plusYears(1).atDay(1).minusDays(1);
            attendanceLQW.between(Attendance::getClockingDate, yearStartDate, yearEndDate);
        } else if (attendanceDto.getYearMonth() != null) {
            // 根据月查询
            // attendanceLQW.apply("DATE_FORMAT(clocking_date, '%Y-%m') =
            // {0}",attendanceDto.getYearMonth());
            // 月的第一天
            LocalDate monthStartDate = attendanceDto.getYearMonth().atDay(1);
            LocalDate monthEndDate = attendanceDto.getYearMonth().plusMonths(1).atDay(1).minusDays(1);
            attendanceLQW.between(Attendance::getClockingDate, monthStartDate, monthEndDate);
        } else if (attendanceDto.getYearMonthDay() != null) {
            // 根据日查询
            attendanceLQW.eq(Attendance::getClockingDate, attendanceDto.getYearMonthDay());
        } else {
            // 默认按当前月查询
            // 获取当前月份
            YearMonth yearMonth = YearMonth.now();
            // attendanceLQW.apply("DATE_FORMAT(clocking_date, '%Y-%m') = {0}",yearMonth);
            LocalDate monthStartDate = yearMonth.atDay(1);
            attendanceLQW.between(Attendance::getClockingDate, monthStartDate, LocalDate.now());
        }
        List<Attendance> attendanceList = attendanceMapper.selectPage(page, attendanceLQW).getRecords();
        List<AttendanceVo> attendanceVoList = new ArrayList<>();
        if (attendanceList.size() > 0) {
            Set<String> clockinRuleIdList = attendanceList.stream().map(Attendance::getClockinRuleId)
                    .collect(Collectors.toSet());
            List<ClockinRule> clockinRuleList = clockinRuleMapper.selectBatchByIdWithDelete(clockinRuleIdList);
            Map<String, ClockinRule> clockinRuleMap = clockinRuleList.stream()
                    .collect(Collectors.toMap(ClockinRule::getId, Function.identity()));
            attendanceVoList.addAll(getUserAttendanceVoList(attendanceList, clockinRuleMap));
        }
        Map<String, Object> map = new HashMap<>();
        map.put("total", page.getTotal());
        map.put("attendanceList", attendanceVoList);
        return Result.success("查询成功", map);
    }

    @Override
    public Result getUserAttendance(AttendanceDto attendanceDto) {
        if (attendanceDto == null) {
            // attendanceDto为空
            attendanceDto = new AttendanceDto();
            // 默认获取当前登录用户
            attendanceDto.setEmployeeId(StpUtil.getLoginIdAsString());
            // 默认获取今天日期
            attendanceDto.setClockingDate(LocalDate.now());
        } else {
            // 用户id为空默认获取当前登录用户
            if (attendanceDto.getEmployeeId() == null) {
                attendanceDto.setEmployeeId(StpUtil.getLoginIdAsString());
            }
            // 打卡日期为空默认获取今天日期
            if (attendanceDto.getClockingDate() == null) {
                attendanceDto.setClockingDate(LocalDate.now());
            }
        }
        LambdaQueryWrapper<Attendance> attendanceLQW = new LambdaQueryWrapper<>();
        attendanceLQW.eq(Attendance::getEmployeeId, attendanceDto.getEmployeeId())
                .eq(Attendance::getClockingDate, attendanceDto.getClockingDate());
        Attendance attendance = attendanceMapper.selectOne(attendanceLQW);
        AttendanceVo attendanceVo = new AttendanceVo();
        ClockinRuleVo clockinRuleVo = new ClockinRuleVo();
        if (attendance != null) {
            List<Attendance> attendanceList = new ArrayList<>();
            attendanceList.add(attendance);
            ClockinRule clockinRule = clockinRuleMapper.selectByIdOnDelete(attendance.getClockinRuleId());
            BeanUtils.copyProperties(clockinRule, clockinRuleVo);
            // 时间处理
            clockinRuleVo.setForenoonCheckinTime(clockinRule.getForenoonCheckinTime().toString());
            clockinRuleVo.setForenoonCheckoutTime(clockinRule.getForenoonCheckoutTime().toString());
            clockinRuleVo.setAfternoonCheckinTime(clockinRule.getAfternoonCheckinTime().toString());
            clockinRuleVo.setAfternoonCheckoutTime(clockinRule.getAfternoonCheckoutTime().toString());
            // 处理打卡位置
            if (clockinRule.getClockinPosition() != null) {
                List<BigDecimal[]> clockinPositionList = new ArrayList<>();
                String[] clockinPositions = clockinRule.getClockinPosition().split(";");
                for (String item : clockinPositions) {
                    clockinPositionList.add(clockinRuleService.getClockinPositionList(item));
                }
                clockinRuleVo.setCoordinate(clockinPositionList);
            }
            Map<String, ClockinRule> clockinRuleMap = new HashMap<>();
            clockinRuleMap.put(clockinRule.getId(), clockinRule);
            attendanceVo = getUserAttendanceVoList(attendanceList, clockinRuleMap).get(0);
        }
        Map<String, Object> map = new HashMap<>();
        map.put("attendanceVo", attendanceVo);
        map.put("clockinRuleVo", clockinRuleVo);
        return Result.success("查询成功", map);
    }

    @Override
    public void exportExcel(String filename) {
        // 参数校验
        if (StringUtils.isEmpty(filename)) {
            throw new RuntimeException("文件名称不能为空");
        }

        // 路径安全检查
        Path path = Paths.get(this.excelPath, filename).normalize();
        if (!path.startsWith(this.excelPath)) {
            throw new RuntimeException("非法文件路径");
        }

        try (InputStream is = new BufferedInputStream(FileUtil.getInputStream(path));
             OutputStream os = new BufferedOutputStream(response.getOutputStream())) {

            // ========== 关键修复点 ==========
            // 1. 修正MIME类型为旧版Excel
            response.reset();
            response.setContentType("application/vnd.ms-excel"); // 关键修改点：.xls对应MIME类型

            // 2. 确保文件名后缀为.xls
            String safeFilename = filename.endsWith(".xls") ? filename : filename + ".xls";
            String encodedFilename = URLEncoder.encode(safeFilename, String.valueOf(StandardCharsets.UTF_8))
                    .replace("+", "%20");
            response.setHeader("Content-Disposition",
                    "attachment; filename=\"" + encodedFilename + "\"");

            // 3. 直接拷贝文件流
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = is.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.flush();

        } catch (IOException e) {
            throw new RuntimeException("文件导出失败: " + e.getMessage(), e);
        }
    }

    /**
     * 处理出勤记录
     * 
     * @param attendanceList
     * @param clockinRuleMap
     * @return
     */
    @Transactional
    protected List<AttendanceVo> getUserAttendanceVoList(List<Attendance> attendanceList,
            Map<String, ClockinRule> clockinRuleMap) {
        List<AttendanceVo> attendanceVoList = new ArrayList<>();
        List<Attendance> newAttendanceList = new ArrayList<>();
        for (Attendance attendance : attendanceList) {
            AttendanceVo attendanceVo = new AttendanceVo();
            attendanceVo.setForenoonCheckinStatus(0);
            attendanceVo.setForenoonCheckoutStatus(0);
            attendanceVo.setAfternoonCheckinStatus(0);
            attendanceVo.setAfternoonCheckoutStatus(0);
            // 查询打卡规则
            ClockinRule clockinRule = clockinRuleMap.get(attendance.getClockinRuleId());
            // 上午签到时间，向后推1分钟
            Time FCheckinTime = Time.valueOf(clockinRule.getForenoonCheckinTime().toLocalTime().plusMinutes(1));
            // 上午签退时间
            Time FCheckoutTime = clockinRule.getForenoonCheckoutTime();

            // 下午签到时间，向后推1分钟
            Time ACheckinTime = Time.valueOf(clockinRule.getAfternoonCheckinTime().toLocalTime().plusMinutes(1));
            // 下午签退时间
            Time ACheckoutTime = clockinRule.getAfternoonCheckoutTime();

            // 现在时间
            Time nowTime = Time.valueOf(LocalTime.now());
            // 判断打卡日期
            if (LocalDate.now().compareTo(attendance.getClockingDate()) == 0) {
                // 打卡日期为今天
                if (attendance.getClockinType() != 1 && attendance.getClockinType() != 2 && DateUtils.compareToTime(nowTime, ACheckinTime) < 0 &&
                        !BaseEnum.CLOCKIN_STATUS_LEAVE.getCodeInt().equals(attendance.getForenoonStatus())) {
                    // 现在时间小于下午签到时间，且上午状态不为请假
                    // 上午
                    if (attendance.getForenoonCheckinTime() == null && attendance.getForenoonCheckoutTime() == null &&
                            DateUtils.compareToTime(nowTime, FCheckoutTime) >= 0) {
                        // 上午签到时间为空，且上午签退时间为空，且现在时间大于等于上午签退时间
                        // 旷工
                        attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_ABSENTEEISM.getCodeInt());
                    }
                    if (attendance.getForenoonCheckinTime() != null && attendance.getForenoonCheckoutTime() == null) {
                        // 上午签到不等于空，且上午签退等于空
                        if (DateUtils.compareToTime(attendance.getForenoonCheckinTime(), FCheckinTime) < 0) {
                            // 上午签到时间小于规则上午签到时间
                            // 正常打卡
                            attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_NORMAL.getCodeInt());
                        } else if (DateUtils.compareToTime(attendance.getForenoonCheckinTime(), FCheckinTime) >= 0) {
                            // 上午签到时间大于等于规则上午签到时间
                            // 迟到
                            attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_BE_LATE.getCodeInt());
                        }
                    } else if (attendance.getForenoonCheckinTime() != null
                            && attendance.getForenoonCheckoutTime() != null) {
                        // 上午签到时间不等于空，且上午签退时间不等于空
                        if (DateUtils.compareToTime(attendance.getForenoonCheckinTime(), FCheckinTime) < 0 &&
                                DateUtils.compareToTime(attendance.getForenoonCheckoutTime(), FCheckoutTime) >= 0) {
                            // 上午签到时间小于规则上午签到时间，且上午签退时间大于等于规则签退时间
                            // 正常打卡
                            attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_NORMAL.getCodeInt());
                        } else if (DateUtils.compareToTime(attendance.getForenoonCheckinTime(), FCheckinTime) > 0 &&
                                DateUtils.compareToTime(attendance.getForenoonCheckoutTime(), FCheckoutTime) >= 0) {
                            // 上午签到时间大于规则上午签到时间，且上午签退时间大于等于规则签退时间
                            // 迟到
                            attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_BE_LATE.getCodeInt());
                        } else if (DateUtils.compareToTime(attendance.getForenoonCheckinTime(), FCheckinTime) < 0 &&
                                DateUtils.compareToTime(attendance.getForenoonCheckoutTime(), FCheckoutTime) < 0) {
                            // 上午签到时间小于规则上午签到时间，且上午签退时间小于规则签退时间
                            // 早退
                            attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_LEAVE_EARLY.getCodeInt());
                        } else if (DateUtils.compareToTime(attendance.getForenoonCheckinTime(), FCheckinTime) > 0 &&
                                DateUtils.compareToTime(attendance.getForenoonCheckoutTime(), FCheckoutTime) < 0) {
                            // 上午签到时间大于规则上午签到时间，且上午签退时间小于规则签退时间
                            // 迟到+早退
                            attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_BE_LATE_LEAVE_EARLY.getCodeInt());
                        }
                    }
                } else if (attendance.getClockinType() != 1 && attendance.getClockinType() != 2 && DateUtils.compareToTime(nowTime, ACheckinTime) > 0 &&
                        !BaseEnum.CLOCKIN_STATUS_LEAVE.getCodeInt().equals(attendance.getAfternoonStatus())) {
                    // 现在时间大于下午签到时间，且下午状态不等于请假
                    // 下午
                    if (attendance.getForenoonCheckinTime() == null && attendance.getForenoonCheckoutTime() == null &&
                            DateUtils.compareToTime(nowTime, FCheckoutTime) >= 0) {
                        // 上午签到时间为空，且上午签退时间为空，且现在时间大于等于上午签退时间
                        // 旷工
                        attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_ABSENTEEISM.getCodeInt());
                    }
                    if (attendance.getForenoonCheckinTime() != null && attendance.getForenoonCheckoutTime() == null &&
                            (attendance.getForenoonStatus() == null || !attendance.getForenoonStatus()
                                    .equals(BaseEnum.CLOCKIN_STATUS_LEAVE.getCodeInt()))) {
                        // 上午签到时间不为空，且上午签退时间为空，且上午状态为空或者不等于请假
                        if (DateUtils.compareToTime(attendance.getForenoonCheckinTime(), FCheckinTime) < 0) {
                            // 上午签到时间小于规则上午签到时间
                            // 未签退
                            attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_Not_signed_out.getCodeInt());
                        } else if (DateUtils.compareToTime(attendance.getForenoonCheckinTime(), FCheckinTime) >= 0) {
                            // 上午签到时间大于等于规则上午签到时间
                            // 迟到+未签退
                            attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_BE_LATE_Not_signed_out.getCodeInt());
                        }
                    }

                    if (attendance.getAfternoonCheckinTime() == null && attendance.getAfternoonCheckoutTime() == null &&
                            DateUtils.compareToTime(nowTime, ACheckoutTime) >= 0) {
                        // 下午签到时间为空，且下午签退时间为空，且当前时间大于规则下午签退时间
                        // 旷工
                        attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_ABSENTEEISM.getCodeInt());
                    }
                    if (attendance.getAfternoonCheckinTime() != null && attendance.getAfternoonCheckoutTime() == null) {
                        // 下午签到时间不等于空，且下午签退时间等于空
                        if (DateUtils.compareToTime(attendance.getAfternoonCheckinTime(), ACheckinTime) < 0) {
                            // 下午签到时间小于规则下午签到时间
                            // 正常打卡
                            attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_NORMAL.getCodeInt());
                        } else if (DateUtils.compareToTime(attendance.getAfternoonCheckinTime(), ACheckinTime) >= 0) {
                            // 下午签到时间大于等于规则下午签到时间
                            // 迟到
                            attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_BE_LATE.getCodeInt());
                        }
                    } else if (attendance.getAfternoonCheckinTime() != null
                            && attendance.getAfternoonCheckoutTime() != null) {
                        // 下午签到时间不等于空，且下午签退时间不等于空
                        if (DateUtils.compareToTime(attendance.getAfternoonCheckinTime(), ACheckinTime) < 0 &&
                                DateUtils.compareToTime(attendance.getAfternoonCheckoutTime(), ACheckoutTime) >= 0) {
                            // 下午签到时间小于规则下午签到时间，且下午签退时间大于等于规则签退时间
                            // 正常打卡
                            attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_NORMAL.getCodeInt());
                        } else if (DateUtils.compareToTime(attendance.getAfternoonCheckinTime(), ACheckinTime) > 0 &&
                                DateUtils.compareToTime(attendance.getAfternoonCheckoutTime(), ACheckoutTime) >= 0) {
                            // 下午签到时间大于规则下午签到时间，且下午签退时间大于等于规则签退时间
                            // 迟到
                            attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_BE_LATE.getCodeInt());
                        } else if (DateUtils.compareToTime(attendance.getAfternoonCheckinTime(), ACheckinTime) < 0 &&
                                DateUtils.compareToTime(attendance.getAfternoonCheckoutTime(), ACheckoutTime) < 0) {
                            // 下午签到时间小于规则下午签到时间，且下午签退时间小于规则签退时间
                            // 早退
                            attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_LEAVE_EARLY.getCodeInt());
                        } else if (DateUtils.compareToTime(attendance.getAfternoonCheckinTime(), ACheckinTime) > 0 &&
                                DateUtils.compareToTime(attendance.getAfternoonCheckoutTime(), ACheckoutTime) < 0) {
                            // 下午签到时间大于规则下午签到时间，且下午签退时间小于规则签退时间
                            // 迟到+早退
                            attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_BE_LATE_LEAVE_EARLY.getCodeInt());
                        }
                    }
                }else if(attendance.getClockinType() == 1 && attendance.getClockinType() == 2 ){
                    if (attendance.getForenoonCheckinTime() != null && attendance.getAfternoonCheckoutTime() != null) {
                        attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_NORMAL.getCodeInt());
                    }
                    if (attendance.getAfternoonCheckinTime() != null && attendance.getAfternoonCheckoutTime() != null) {
                        attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_NORMAL.getCodeInt());
                    }
                }
            } else if (LocalDate.now().compareTo(attendance.getClockingDate()) > 0) {
                // 打卡日期小于今天
                // 上午
                if (attendance.getClockinType() != 1 && attendance.getClockinType() != 2 && attendance.getForenoonCheckinTime() == null && attendance.getForenoonCheckoutTime() == null &&
                        !BaseEnum.CLOCKIN_STATUS_LEAVE.getCodeInt().equals(attendance.getForenoonStatus())) {
                    // 上午签到时间为空，上午签退时间为空，上午状态不等于请假
                    // 旷工
                    attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_ABSENTEEISM.getCodeInt());
                } else if (attendance.getClockinType() != 1 && attendance.getClockinType() != 2 && attendance.getForenoonCheckinTime() != null
                        && attendance.getForenoonCheckoutTime() == null) {
                    // 上午签到时间不等于空，且上午签退时间等于空
                    if (DateUtils.compareToTime(attendance.getForenoonCheckinTime(), FCheckinTime) < 0) {
                        // 上午签到时间小于规则上午签到时间
                        // 未签退
                        attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_Not_signed_out.getCodeInt());
                    } else if (DateUtils.compareToTime(attendance.getForenoonCheckinTime(), FCheckinTime) >= 0) {
                        // 上午签到时间大于等于规则上午签到时间
                        // 迟到+未签退
                        attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_BE_LATE_Not_signed_out.getCodeInt());
                    }
                } else if (attendance.getClockinType() != 1 && attendance.getClockinType() != 2 && attendance.getForenoonCheckinTime() != null
                        && attendance.getForenoonCheckoutTime() != null) {
                    // 上午签到时间不等于空，且上午签退时间不等于空
                    if (DateUtils.compareToTime(attendance.getForenoonCheckinTime(), FCheckinTime) < 0 &&
                            DateUtils.compareToTime(attendance.getForenoonCheckoutTime(), FCheckoutTime) >= 0) {
                        // 上午签到时间小于规则上午签到时间，且上午签退时间大于等于规则签退时间
                        // 正常打卡
                        attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_NORMAL.getCodeInt());
                    } else if (DateUtils.compareToTime(attendance.getForenoonCheckinTime(), FCheckinTime) > 0 &&
                            DateUtils.compareToTime(attendance.getForenoonCheckoutTime(), FCheckoutTime) >= 0) {
                        // 上午签到时间大于规则上午签到时间，且上午签退时间大于等于规则签退时间
                        // 迟到
                        attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_BE_LATE.getCodeInt());
                    } else if (DateUtils.compareToTime(attendance.getForenoonCheckinTime(), FCheckinTime) < 0 &&
                            DateUtils.compareToTime(attendance.getForenoonCheckoutTime(), FCheckoutTime) < 0) {
                        // 上午签到时间小于规则上午签到时间，且上午签退时间小于规则签退时间
                        // 早退
                        attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_LEAVE_EARLY.getCodeInt());
                    } else if (DateUtils.compareToTime(attendance.getForenoonCheckinTime(), FCheckinTime) > 0 &&
                            DateUtils.compareToTime(attendance.getForenoonCheckoutTime(), FCheckoutTime) < 0) {
                        // 上午签到时间大于规则上午签到时间，且上午签退时间小于规则签退时间
                        // 迟到+早退
                        attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_BE_LATE_LEAVE_EARLY.getCodeInt());
                    }
                }
                // 下午
                if (attendance.getClockinType() != 1 && attendance.getClockinType() != 2 && attendance.getAfternoonCheckinTime() == null && attendance.getAfternoonCheckoutTime() == null &&
                        !BaseEnum.CLOCKIN_STATUS_LEAVE.getCodeInt().equals(attendance.getAfternoonStatus())) {
                    // 下午签到时间为空，下午签退时间为空，下午状态不等于请假
                    // 旷工
                    attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_ABSENTEEISM.getCodeInt());
                } else if (attendance.getClockinType() != 1 && attendance.getClockinType() != 2 && attendance.getAfternoonCheckinTime() != null
                        && attendance.getAfternoonCheckoutTime() == null) {
                    // 下午签到不等于空，且下午签退等于空
                    if (DateUtils.compareToTime(attendance.getAfternoonCheckinTime(), ACheckinTime) < 0) {
                        // 下午签到小于规则下午签到时间
                        // 未签退
                        attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_Not_signed_out.getCodeInt());
                    } else if (DateUtils.compareToTime(attendance.getAfternoonCheckinTime(), ACheckinTime) >= 0) {
                        // 下午签到大于等于规则下午签到时间
                        // 迟到+未签退
                        attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_BE_LATE_Not_signed_out.getCodeInt());
                    }
                } else if (attendance.getClockinType() != 1 && attendance.getClockinType() != 2 && attendance.getAfternoonCheckinTime() != null
                        && attendance.getAfternoonCheckoutTime() != null) {
                    // 下午签到时间不等于空，且下午签退时间不等于空
                    if (DateUtils.compareToTime(attendance.getAfternoonCheckinTime(), ACheckinTime) < 0 &&
                            DateUtils.compareToTime(attendance.getAfternoonCheckoutTime(), ACheckoutTime) >= 0) {
                        // 下午签到时间小于规则下午签到时间，且下午签退时间大于等于规则签退时间
                        // 正常打卡
                        attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_NORMAL.getCodeInt());
                    } else if (DateUtils.compareToTime(attendance.getAfternoonCheckinTime(), ACheckinTime) > 0 &&
                            DateUtils.compareToTime(attendance.getAfternoonCheckoutTime(), ACheckoutTime) >= 0) {
                        // 下午签到时间大于规则下午签到时间，且下午签退时间大于等于规则签退时间
                        // 迟到
                        attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_BE_LATE.getCodeInt());
                    } else if (DateUtils.compareToTime(attendance.getAfternoonCheckinTime(), ACheckinTime) < 0 &&
                            DateUtils.compareToTime(attendance.getAfternoonCheckoutTime(), ACheckoutTime) < 0) {
                        // 下午签到时间小于规则下午签到时间，且下午签退时间小于规则签退时间
                        // 早退
                        attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_LEAVE_EARLY.getCodeInt());
                    } else if (DateUtils.compareToTime(attendance.getAfternoonCheckinTime(), ACheckinTime) > 0 &&
                            DateUtils.compareToTime(attendance.getAfternoonCheckoutTime(), ACheckoutTime) < 0) {
                        // 下午签到时间大于规则下午签到时间，且下午签退时间小于规则签退时间
                        // 迟到+早退
                        attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_BE_LATE_LEAVE_EARLY.getCodeInt());
                    }
                }
                if (attendance.getClockinType() == 1 && attendance.getClockinType() == 2) {
                    if (attendance.getForenoonCheckinTime() != null && attendance.getAfternoonCheckoutTime() != null) {
                        attendance.setForenoonStatus(BaseEnum.CLOCKIN_STATUS_NORMAL.getCodeInt());
                    }
                    if (attendance.getAfternoonCheckinTime() != null && attendance.getAfternoonCheckoutTime() != null) {
                        attendance.setAfternoonStatus(BaseEnum.CLOCKIN_STATUS_NORMAL.getCodeInt());
                    }
                }
            }

            if (attendance.getForenoonStatus() != null) {
                if (attendance.getForenoonStatus() == 3 || attendance.getForenoonStatus() == 4) {
                    // 上午状态为旷工或者请假
                    if (attendance.getForenoonStatus() == 3) {
                        // 旷工
                        attendanceVo.setForenoonCheckinStatus(3);
                        attendanceVo.setForenoonCheckoutStatus(3);
                    } else {
                        // 请假
                        attendanceVo.setForenoonCheckinStatus(4);
                        attendanceVo.setForenoonCheckoutStatus(4);
                    }
                }
                if (attendance.getForenoonStatus() == 0) {
                    // 上午状态为正常
                    if (attendance.getForenoonCheckoutTime() != null) {
                        // 上午签退时间不为空
                        attendanceVo.setForenoonCheckinStatus(1);
                        attendanceVo.setForenoonCheckoutStatus(1);
                    } else {
                        attendanceVo.setForenoonCheckinStatus(1);
                    }
                } else if (attendance.getForenoonStatus() == 1) {
                    // 上午状态为迟到
                    if (attendance.getForenoonCheckoutTime() != null) {
                        // 上午签退时间不为空
                        attendanceVo.setForenoonCheckinStatus(2);
                        attendanceVo.setForenoonCheckoutStatus(1);
                    } else {
                        attendanceVo.setForenoonCheckinStatus(2);
                    }
                } else if (attendance.getForenoonStatus() == 2) {
                    // 上午状态为早退
                    attendanceVo.setForenoonCheckinStatus(1);
                    attendanceVo.setForenoonCheckoutStatus(2);
                } else if (attendance.getForenoonStatus() == 5) {
                    // 上午状态为迟到加早退
                    attendanceVo.setForenoonCheckinStatus(2);
                    attendanceVo.setForenoonCheckoutStatus(2);
                } else if (attendance.getForenoonStatus() == 6) {
                    // 上午状态为未签退
                    attendanceVo.setForenoonCheckinStatus(1);
                    attendanceVo.setForenoonCheckoutStatus(5);
                } else if (attendance.getForenoonStatus() == 7) {
                    // 上午状态为迟到加未签退
                    attendanceVo.setForenoonCheckinStatus(2);
                    attendanceVo.setForenoonCheckoutStatus(5);
                }
            }

            if (attendance.getAfternoonStatus() != null) {
                if (attendance.getAfternoonStatus() == 3 || attendance.getAfternoonStatus() == 4) {
                    // 下午状态为旷工或者请假
                    if (attendance.getAfternoonStatus() == 3) {
                        // 旷工
                        attendanceVo.setAfternoonCheckinStatus(3);
                        attendanceVo.setAfternoonCheckoutStatus(3);
                    } else {
                        // 请假
                        attendanceVo.setAfternoonCheckinStatus(4);
                        attendanceVo.setAfternoonCheckoutStatus(4);
                    }
                }
                if (attendance.getAfternoonStatus() == 0) {
                    // 下午状态为正常
                    if (attendance.getAfternoonCheckoutTime() != null) {
                        // 下午签退时间不为空
                        attendanceVo.setAfternoonCheckinStatus(1);
                        attendanceVo.setAfternoonCheckoutStatus(1);
                    } else {
                        attendanceVo.setAfternoonCheckinStatus(1);
                    }
                } else if (attendance.getAfternoonStatus() == 1) {
                    // 下午状态为迟到
                    if (attendance.getAfternoonCheckoutTime() != null) {
                        // 上午签退时间不为空
                        attendanceVo.setAfternoonCheckinStatus(2);
                        attendanceVo.setAfternoonCheckoutStatus(1);
                    } else {
                        attendanceVo.setAfternoonCheckinStatus(2);
                    }
                } else if (attendance.getAfternoonStatus() == 2) {
                    // 下午状态为早退
                    attendanceVo.setAfternoonCheckinStatus(1);
                    attendanceVo.setAfternoonCheckoutStatus(2);
                } else if (attendance.getAfternoonStatus() == 5) {
                    // 下午状态为迟到加早退
                    attendanceVo.setAfternoonCheckinStatus(2);
                    attendanceVo.setAfternoonCheckoutStatus(2);
                } else if (attendance.getAfternoonStatus() == 6) {
                    // 下午状态为未签退
                    attendanceVo.setAfternoonCheckinStatus(1);
                    attendanceVo.setAfternoonCheckoutStatus(5);
                } else if (attendance.getAfternoonStatus() == 7) {
                    // 下午状态为迟到加未签退
                    attendanceVo.setAfternoonCheckinStatus(2);
                    attendanceVo.setAfternoonCheckoutStatus(5);
                }
            }

            // 添加到更新数据集合
            newAttendanceList.add(attendance);

            BeanUtils.copyProperties(attendance, attendanceVo);
            // 设置正常打卡时间
            if (attendance.getForenoonCheckinTime() == null) {
                attendanceVo.setForenoonCheckin("未打卡（" + clockinRule.getForenoonCheckinTime() + "）");
            } else {
                attendanceVo.setForenoonCheckin(
                        attendance.getForenoonCheckinTime() + "（" + clockinRule.getForenoonCheckinTime() + "）");
            }
            if (attendance.getForenoonCheckoutTime() == null) {
                attendanceVo.setForenoonCheckout("未打卡（" + clockinRule.getForenoonCheckoutTime() + "）");
            } else {
                attendanceVo.setForenoonCheckout(
                        attendance.getForenoonCheckoutTime() + "（" + clockinRule.getForenoonCheckoutTime() + "）");
            }
            if (attendance.getAfternoonCheckinTime() == null) {
                attendanceVo.setAfternoonCheckin("未打卡（" + clockinRule.getAfternoonCheckinTime() + "）");
            } else {
                attendanceVo.setAfternoonCheckin(
                        attendance.getAfternoonCheckinTime() + "（" + clockinRule.getAfternoonCheckinTime() + "）");
            }
            if (attendance.getAfternoonCheckoutTime() == null) {
                attendanceVo.setAfternoonCheckout("未打卡（" + clockinRule.getAfternoonCheckoutTime() + "）");
            } else {
                attendanceVo.setAfternoonCheckout(
                        attendance.getAfternoonCheckoutTime() + "（" + clockinRule.getAfternoonCheckoutTime() + "）");
            }
            attendanceVoList.add(attendanceVo);
        }
        // 更新数据
        attendanceMapper.updateBatchById(newAttendanceList);
        return attendanceVoList;
    }
}
